/*
 * Copyright (c) 2018-2999 湖南洛云网络科技有限公司 All rights reserved.
 *
 * https://www.gz-yami.com/
 *
 */

package com.yami.shop.seckill.api.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.StrUtil;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.yami.shop.bean.app.dto.OrderNumbersDto;
import com.yami.shop.bean.app.dto.UserAddrDto;
import com.yami.shop.bean.app.param.OrderShopParam;
import com.yami.shop.bean.event.CalculateTransfeeEvent;
import com.yami.shop.bean.model.Product;
import com.yami.shop.bean.model.Sku;
import com.yami.shop.bean.model.UserAddr;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.i18n.I18nMessage;
import com.yami.shop.common.util.Arith;
import com.yami.shop.seckill.api.param.ConfirmParam;
import com.yami.shop.seckill.api.service.SeckillCacheManager;
import com.yami.shop.seckill.comment.dto.SeckillOrderMergerDto;
import com.yami.shop.seckill.comment.dto.SeckillShopCartItemDto;
import com.yami.shop.seckill.comment.model.Seckill;
import com.yami.shop.seckill.comment.model.SeckillSku;
import com.yami.shop.seckill.comment.service.SeckillOrderService;
import com.yami.shop.seckill.comment.service.SeckillService;
import com.yami.shop.seckill.comment.service.SeckillSkuService;
import com.yami.shop.security.api.util.SecurityUtils;
import com.yami.shop.service.OrderService;
import com.yami.shop.service.ProductService;
import com.yami.shop.service.SkuService;
import com.yami.shop.service.UserAddrService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import ma.glasnost.orika.MapperFacade;
import org.springframework.context.ApplicationContext;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.*;


/**
 * 秒杀信息
 *
 * @author LGH
 * @date 2019-08-28 09:36:59
 */
@RestController
@AllArgsConstructor
@RequestMapping("/p/seckill" )
@Api(tags = "秒杀订单接口")
public class SeckillOrderController {

    private final SeckillService seckillService;

    private final MapperFacade mapperFacade;

    private final ProductService productService;

    private final SeckillSkuService seckillSkuService;

    private final SkuService skuService;

    private final UserAddrService userAddrService;


    private final SeckillOrderService seckillOrderService;

    private final ApplicationContext applicationContext;

    private final SeckillCacheManager seckillCacheManager;

    private final Snowflake snowflake;

    private final OrderService orderService;

    private static Executor executor = new ThreadPoolExecutor(
            5,
            20,
            5L,
            TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(1000),
            new ThreadFactoryBuilder()
                    .setNameFormat("seckill-redis-listener-pool-%d").build());



    @ApiOperation(value = "获取秒杀订单路径")
    @GetMapping(value="/orderPath")
    public ResponseEntity<String> getOrderPath() {

        String userId = SecurityUtils.getUser().getUserId();

        String orderPath = seckillCacheManager.createOrderPath(userId);

        return ResponseEntity.ok(orderPath);
    }


    @ApiOperation(value = "确认订单")
    @PostMapping(value="/{orderPath}/confirm")
    public ResponseEntity<SeckillOrderMergerDto> confirm(@PathVariable("orderPath") String orderPath, @Valid @RequestBody ConfirmParam confirmParam) {

        String userId = SecurityUtils.getUser().getUserId();
        seckillCacheManager.checkOrderPath(userId,orderPath);

        // 秒杀sku（来自缓存），注：千万不要用这里的库存校验
        SeckillSku seckillSku = seckillSkuService.getSeckillSkuById(confirmParam.getSeckillSkuId());


        if (seckillSku == null) {
            // 购物车包含无法识别的商品
            throw new YamiShopBindException("yami.shop.cart.prod.unrecognized");
        }

        Seckill seckill = seckillService.getSeckillById(seckillSku.getSeckillId());

        if (new Date().before(seckill.getStartTime())){
            throw new YamiShopBindException("yami.seckill.order.less.start.time.error");
        }
        if (new Date().after(seckill.getEndTime())){
            throw new YamiShopBindException("yami.seckill.order.more.end.time.error");
        }

        // 订单的地址信息
        UserAddr userAddr = userAddrService.getUserAddrByUserId(confirmParam.getAddrId(), userId);
        UserAddrDto userAddrDto = mapperFacade.map(userAddr, UserAddrDto.class);

        // 获取sku信息
//        Sku sku = skuService.getSkuBySkuId(seckillSku.getSkuId(), I18nMessage.getDbLang())
        Sku sku = skuService.getSkuAndLangBySkuId(seckillSku.getSkuId(), I18nMessage.getDbLang());
        // 商品信息（来自缓存），注：千万不要用这里的库存校验
        Product product = productService.getProductByProdId(sku.getProdId(), I18nMessage.getDbLang());

        double actualTotal = Arith.mul(confirmParam.getProdCount(), seckillSku.getSeckillPrice());
        double total = Arith.mul(confirmParam.getProdCount(), sku.getPrice());

        SeckillShopCartItemDto shopCartItem = new SeckillShopCartItemDto();
        shopCartItem.setProdName(sku.getProdName());
        shopCartItem.setProdNameCn(sku.getProdNameCn());
        shopCartItem.setProdNameEn(sku.getProdNameEn());
        shopCartItem.setProdId(product.getProdId());
        shopCartItem.setProdCount(confirmParam.getProdCount());
        // 商品总价格为：秒杀商品数量 * 秒杀价格
        shopCartItem.setProductTotalAmount(total);
        shopCartItem.setSkuId(sku.getSkuId());
        shopCartItem.setBasketDate(new Date());
        shopCartItem.setShareReduce(0.0);
        shopCartItem.setActualTotal(actualTotal);
        shopCartItem.setShopId(product.getShopId());
        shopCartItem.setSkuName(sku.getSkuName());
        shopCartItem.setPic(StrUtil.isBlank(sku.getPic())? product.getPic() : sku.getPic());
        shopCartItem.setSeckillSkuId(seckillSku.getSeckillSkuId());
        shopCartItem.setSeckillId(seckillSku.getSeckillId());
        shopCartItem.setPrice(sku.getPrice());
        shopCartItem.setSeckillPrice(seckillSku.getSeckillPrice());
        //设置分销员卡号
        shopCartItem.setDistributionCardNo(confirmParam.getDistributionCardNo());
        // 用户地址如果为空，则表示该用户从未设置过任何地址相关信息
        double transFee = 0.0;
        if (userAddr != null) {
            // 每个产品的运费相加(运费模板有缓存)
            CalculateTransfeeEvent calculateTransfeeEvent = new CalculateTransfeeEvent(shopCartItem, userAddr);
            applicationContext.publishEvent(calculateTransfeeEvent);
            transFee = calculateTransfeeEvent.getTransfee();
        }

        // 计算秒杀优惠
        double reduce = Arith.mul(Arith.sub(shopCartItem.getPrice(),shopCartItem.getSeckillPrice()),shopCartItem.getProdCount());

        SeckillOrderMergerDto dto = new SeckillOrderMergerDto();
        dto.setSeckillReduce(reduce);
        dto.setActualTotal(Arith.add(actualTotal, transFee));
        dto.setShopCartItem(shopCartItem);
        dto.setTotal(total);
        dto.setTotalCount(shopCartItem.getProdCount());
        dto.setUserAddr(userAddrDto);
        dto.setTransfee(transFee);

        seckillOrderService.putConfirmOrderCache(userId,dto);

        return ResponseEntity.ok(dto);
    }

    /**
     * 购物车/立即购买  提交订单,根据店铺拆单
     */
    @PostMapping("/{orderPath}/submit")
    @ApiOperation(value = "提交订单", notes = "提交之后返回WebSocket路径，请求对应的WebSocket路径，开始等待响应")
    public ResponseEntity<OrderNumbersDto> submitOrders(@PathVariable("orderPath") String orderPath, @Valid @RequestBody OrderShopParam orderShopParam) {
        String userId = SecurityUtils.getUser().getUserId();

        // 验证订单路径
        seckillCacheManager.checkOrderPath(userId,orderPath);

        SeckillOrderMergerDto dto = seckillOrderService.getConfirmOrderCache(userId);

        if (dto == null) {
            //订单已过期，请重新下单
            throw new YamiShopBindException("yami.order.expired");
        }

        if (dto.getUserAddr() == null) {
            // 请填写收货地址
            throw new YamiShopBindException("yami.delivery.address");
        }

        SeckillShopCartItemDto shopCartItem = dto.getShopCartItem();


        // 秒杀活动信息（来自缓存）
        Seckill seckill = seckillService.getSeckillById(shopCartItem.getSeckillId());

        // 秒杀已经下线
        if (Objects.equals(seckill.getStatus(), 0) || DateUtil.compare(seckill.getStartTime(),new Date()) > 0
                || DateUtil.compare(seckill.getEndTime(),new Date()) < 0) {
            // 秒杀活动未开始或已结束
            throw new YamiShopBindException("yami.seckill.exception");
        }

        // 这里一进来就减库存，但是为了防止少卖，120秒会自己更新库存~因为缓存只有60秒
        seckillCacheManager.decrSeckillSkuStocks(shopCartItem.getSeckillSkuId(),shopCartItem.getSeckillId(), shopCartItem.getProdCount());



        // 判断之前秒杀的商品有没有超过限制，-1表示商品不限制秒杀数量
        seckillOrderService.checkOrderProdNum(seckill, userId, shopCartItem.getProdCount());


        dto.setMsgId(orderPath);
        dto.setRemarks(orderShopParam.getRemarks());
        dto.setUserId(userId);
        String orderNumber = String.valueOf(snowflake.nextId());
        dto.setOrderNumber(orderNumber);
        try{
            executor.execute(() -> {
                seckillOrderService.submit(dto);
            });
        }catch (RejectedExecutionException e) {
            // 服务器繁忙，请稍后再试
            throw new YamiShopBindException("yami.network.busy");
        }

        seckillOrderService.removeConfirmOrderCache(userId);

        return ResponseEntity.ok(new OrderNumbersDto(orderNumber));
    }


    @GetMapping("/createOrderStatus")
    @ApiOperation(value = "根据orderNumber获取订单是否创建成功", notes = "订单数量")
    @ApiImplicitParam(name = "orderId", value = "订单流水号", required = true, dataType = "String")
    public ResponseEntity<Integer> getCreateOrderStatus(@RequestParam("orderNumber") String orderNumber) {
        return ResponseEntity.ok(orderService.countByOrderNumber(orderNumber));
    }


}
